package util.parser.wikiXML;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;

import java.util.LinkedList;


import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;

import org.xml.sax.helpers.DefaultHandler;
import  util.wikiXML.objectModel.*;;

public class WikiParser extends DefaultHandler {

	/**
	 * @param args
	 */

	private String tempVal;

	// to maintain context
	private WikiPage wiki;
	private LinkedList<WikiSection> section;

	/*
	 * Temporal variables
	 */

	private String paragraphText;
	private WikiLink tempLink;

	/*
	 * flags
	 */

	boolean articleOn = false;
	boolean categoryOn = false;
	boolean crossLingualOn = false;
	boolean paragraphOn = false;

	public WikiParser() {
		wiki = null;
	}

	public void startDocument() {

		wiki = new WikiPage();
		section = new LinkedList<WikiSection>();

	}

	public WikiPage parseWiki(InputStream in) {

		// get a factory
		SAXParserFactory spf = SAXParserFactory.newInstance();
		try {

			// get a new instance of parser
			SAXParser sp = spf.newSAXParser();

			// parse the file and also register this class for call backs
			sp.parse(in, this);

		} catch (SAXException se) {
			se.printStackTrace();
		} catch (ParserConfigurationException pce) {
			pce.printStackTrace();
		} catch (IOException ie) {
			ie.printStackTrace();
		}

		return wiki;
	}

	/**
	 * Iterate through the list and print the contents
	 */
	private void printData() {

		// System.out.println("No of Employees '" + section.getElements().size()
		// + "'.");

		/*
		 * Iterator it = sections..iterator(); while(it.hasNext()) {
		 * System.out.println(it.next().toString()); }
		 */
	}

	// Event Handlers
	public void startElement(String uri, String localName, String qName,
			Attributes attributes) throws SAXException {

		// we get page name and page id from meta tags
		if (qName.equalsIgnoreCase("meta")) {
			// add pagename and page id

			if (attributes.getValue("name").equalsIgnoreCase("wx_pagename")) {
				wiki.setName(attributes.getValue("content"));

			} else if (attributes.getValue("name").equalsIgnoreCase(
					"wx_page_id")) {

				wiki.setName(attributes.getValue("content"));
			}

		}

		/**
		 * We detect the start of the BODY section of the wikipage, where most
		 * of the content is located
		 */

		if (qName.equalsIgnoreCase("div")
				&& attributes.getValue("id").equalsIgnoreCase("wx_article")) {
			articleOn = true;

		}

		/**
		 * We detect the start of the Category links section of the wikipage,
		 * where most of the content is located
		 */

		if (qName.equalsIgnoreCase("div")
				&& attributes.getValue("id").equalsIgnoreCase(
						"wx_categorylinks")) {
			categoryOn = true;

		}

		/**
		 * We detect the start of the Cross-lingual links section of the
		 * wikipage, where most of the content is located
		 */
		if (qName.equalsIgnoreCase("div")
				&& attributes.getValue("id").equalsIgnoreCase(
						"wx_languagelinks")) {
			crossLingualOn = true;

		}

		// wx:section tag, we create a section element and we add it to a LIFO
		// representing the current section of level 1 processed

		if (qName.equalsIgnoreCase("wx:section")) {

			WikiSection subSection = new WikiSection();
			subSection.setLevel(Integer.valueOf(attributes.getValue("level"))
					.shortValue());
			subSection.setName(attributes.getValue("title"));

			// LIFO structure (necessary to manage nested section structures)
			section.push(subSection);
			System.out.println(attributes.getValue("title"));

		}

		/*
		 * <p> paragraph tags
		 * 
		 * clean the paragraphText and turn on the paragraphOn flag
		 */

		if (qName.equalsIgnoreCase("p") && articleOn == true) {

			paragraphText = "";
			paragraphOn = true;

			WikiParagraph p = new WikiParagraph();

			updateCurrentSegment(p);

		}

		/**
		 * <a> anchor tags
		 * 
		 * We create a WikiLink object, feed it with the attributes of the <a>
		 * tag
		 * 
		 * if the paragraphOn flag is activated, we add the link to the list of
		 * elements of the currentParagraph object
		 */

		if (qName.equalsIgnoreCase("a") && articleOn == true) {

			String tmp_field;
			WikiLink link = new WikiLink();

			tmp_field = attributes.getValue("href");
			if (tmp_field != null && !tmp_field.equals("")) {
				link.setHref(tmp_field);
			}

			tmp_field = attributes.getValue("linktype");
			if (tmp_field != null && !tmp_field.equals("")) {
				link.setType(tmp_field);
			}

			tmp_field = attributes.getValue("title");
			if (tmp_field != null && !tmp_field.equals("")) {
				link.setTitle(tmp_field);
			}

			tmp_field = attributes.getValue("pagename");
			if (tmp_field != null && !tmp_field.equals("")) {
				link.setPageName(tmp_field);
			}

			tmp_field = attributes.getValue("page_id");
			if (tmp_field != null && !tmp_field.equals("")) {
				link.setPageId(tmp_field);
			}

			tmp_field = attributes.getValue("fragment");
			if (tmp_field != null && !tmp_field.equals("")) {
				link.setFragment(tmp_field);
			}

			System.out.println("Link:" + link.getTitle());

			if (paragraphOn = true) {

				updateCurrentParagraph(link);

			} else {
				updateCurrentSegment(link);
			}

		}
		// reset
		tempVal = "";
	}

	public void characters(char[] ch, int start, int length)
			throws SAXException {
		tempVal = new String(ch, start, length);
	}

	public void endElement(String uri, String localName, String qName)
			throws SAXException {

		// we start the wikipage when we end parsing the title
		if (qName.equalsIgnoreCase("title")) {
			// add it to the list

			wiki = new WikiPage();
			wiki.setTitle(tempVal);

		}

		/*
		 * wx:section case We pop the WikiSection object from the LIFO structure
		 * and we add it as new element of the WikiSection element that is now
		 * in the LIFO
		 * 
		 * In case the WiKiSection removed is the only element in the LIFO, we
		 * add it to the sections list of the WikiPage
		 */

		if (qName.equalsIgnoreCase("wx:section")) {
			// add it to the list

			WikiSection top = section.pop();

			if (section.size() > 0) {

				updateCurrentSegment(top);

			} else {
				wiki.addSection(top);
				articleOn = false;

			}

			// System.out.println("out " + top.getName());

		}

		/*
		 * <p> tags
		 * 
		 * Extracts the text of a paragraph and add it to the elements list of
		 * the current Section processed
		 * 
		 * Them, it sets the paragraphOn flag to 0, and clean the paragraph
		 * current text
		 */

		if (qName.equalsIgnoreCase("p") && articleOn == true) {

			paragraphOn = false;

			updateCurrentParagraph(paragraphText);

		}

		/**
		 * <a> tag
		 * 
		 * Extract text and add it to current link
		 * 
		 **/

		if (qName.equalsIgnoreCase("a") && articleOn == true) {

			updateCurrentLink();

		}

	}

	private void updateCurrentSegment(Object element) {

		WikiSection tmp = section.pop();
		tmp.addElement(element);
		section.push(tmp);

	}

	private void updateCurrentLink() {

		WikiSection tmp = section.pop();
		Object t = tmp.getLastElement();
		WikiLink link;

		if (paragraphOn) {
			if (t instanceof WikiParagraph) {
				if (((WikiParagraph) t).getLastElement() instanceof WikiLink) {

					link = (WikiLink) ((WikiParagraph) t).getLastElement();
					link.setText((String) tempVal);

					WikiParagraph p = (WikiParagraph) t;

					p.setText(p.getText() + tempVal);

				} else {
					System.out
							.println("Cast error: Not an instance of WikiLink");

				}

			} else {
				System.out
						.println("Cast error: Not an instance of WikiParagraph");

			}

		} else {

			if (t instanceof WikiLink) {

				link = (WikiLink) t;
				link.setText(tempVal);

			} else {
				System.out.println("Cast error: Not an instance of WikiLink");

			}

		}
		section.push(tmp);

	}

	private void updateCurrentParagraph(Object element) {

		WikiSection tmp = section.pop();
		Object t = tmp.getLastElement();

		if (t instanceof WikiParagraph) {

			WikiParagraph p = (WikiParagraph) t;

			p.addElement(element);

			paragraphText += " " + tempVal;
			p.setText(paragraphText);

			section.push(tmp);

		} else {
			System.out.println("Cast error: Not an instance of WikiParagraph");

		}

	}

	public static WikiPage parseWikiFile(FileInputStream in) {
		WikiParser spe = new WikiParser();

		WikiPage wiki = spe.parseWiki(in);
		spe = null;
		return wiki;

	}

	public static void main(String[] args) {
		WikiParser spe = new WikiParser();

		File file = new File(
				"F:\\data\\gikip\\EN\\en\\1\\9\\9\\1991_Academy_Awards_b141.xml");
		FileInputStream in = null;
		try {
			in = new FileInputStream(file);
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		WikiPage wiki = spe.parseWiki(in);
	//	System.out.println(wiki.getSectionText(0));

	}

}
